#include "globals.h"
#include "bikirom-timers.h"
#include <avr/wdt.h>

//----------------------------------------------------------------------------------------
// Macros

//----------------------------------------------------------------------------------------
// Typedefinitions
typedef struct _typBikTimeVars
{
	uint32_t	nTickMS;		/* Ticks since startup */
	uint16_t	nTicks;			/* Ticks Counter */
	uint8_t		nTickFreq;		/* 1 to 255Hz */
	uint8_t		nStatus:1,		/* Running Status */
				nPause:1;		/* Puase Mode */
	_typTimers	typTimers[TIMERCOUNT];
} _typBikTimeVars;

//----------------------------------------------------------------------------------------
// Static Variables
static struct _typBikTimeVars	typVars;

//----------------------------------------------------------------------------------------
// Private Functions
void btimer_master(void);

//----------------------------------------------------------------------------------------
// Function Bodies
void btimer_init(uint8_t frequency, uint8_t timer, _eTimerInterrupts eInt)
{
	uint8_t i;

	// Initialise the variables
	typVars.nTickFreq = frequency;
	typVars.nTickMS = 0;
	typVars.nStatus = 0;
	typVars.nPause = 0;

	// Initialise the timer interrupts
	timer_initialise_mode(timer, frequency, TIMER_CTC);
	timer_attach(eInt, &btimer_master);

	// Nullify the timers
	for(i=0;i<TIMERCOUNT;i++)
	{
		typVars.typTimers[i].mFncPtr = NULL;
	}

}

uint8_t btimer_add(void (*BikTmrfunc)(void* param), int16_t Paramater, uint32_t Timeout, uint32_t TimeoutOffset, uint8_t Recuring, uint8_t Priority)
{
	uint8_t i;

	for( i=0;i<TIMERCOUNT;i++)
	{
		if (typVars.typTimers[i].mFncPtr == NULL)
		{
			typVars.typTimers[i].mFncPtr = BikTmrfunc;
			typVars.typTimers[i].mFncParam = Paramater;
			typVars.typTimers[i].mOverflowCnt = TimeoutOffset / (1000 / typVars.nTickFreq);
			typVars.typTimers[i].mOverflowReq = Timeout / (1000 / typVars.nTickFreq);
			typVars.typTimers[i].mBRecuring = Recuring;
			typVars.typTimers[i].mPriority = Priority;

			return TRUE;
		}
	}

	// Should never get to here, but if we do... Should most probably send up an error message here to
	// Bikisoft, saying something like, timer buffer overflow or something..
	return FALSE;
}

uint8_t btimer_remove(void (*BikTmrfunc)(void* param))
{
	uint8_t i;

	for( i=0;i<TIMERCOUNT;i++)
	{
		if (typVars.typTimers[i].mFncPtr == BikTmrfunc)
		{
			typVars.typTimers[i].mFncPtr = NULL;
			typVars.typTimers[i].mFncParam = 0;
			typVars.typTimers[i].mOverflowCnt = 0;
			typVars.typTimers[i].mOverflowReq = 0;
			typVars.typTimers[i].mBRecuring = 0;
			typVars.typTimers[i].mPriority = 0;

			return TRUE;
		}
	}

	// Should never get to here, but if we do... Should most probably send up an error message here to
	// Bikisoft, saying something like, timer buffer overflow or something..
	return FALSE;
}

void btimer_pause(uint8_t bPause)
{
	typVars.nPause = bPause ? 1 : 0;
}

// Timer Master point of execution
void btimer_master(void)
{
	unsigned char i;

	typVars.nTickMS += 1;
	wdt_reset();

	if (typVars.nPause)
		return;

	outb(TICKS_CNT,0);

	// Only go forward if you can, no nested interrupts!
	if (typVars.nStatus)
	{
		return;
	}
	else
	{
		typVars.nStatus = TRUE;
	}

	sei();
	
	for(i=0;i<TIMERCOUNT;i++)
	{
		if (typVars.typTimers[i].mFncPtr != NULL)
		{
			// Increment the overflow counter
			typVars.typTimers[i].mOverflowCnt++;
			// Execute the function is the delay has been met
			if (typVars.typTimers[i].mOverflowCnt >= typVars.typTimers[i].mOverflowReq)
			{
				// Prevent the thread from being executed again if it is already being run
				if (typVars.typTimers[i].mRunning == 0)
				{
					// Lock the thread
					typVars.typTimers[i].mRunning = 1;
					typVars.typTimers[i].mFncPtr(&typVars.typTimers[i]);
					// Reset the Watch Dog Timer
					wdt_reset();
					// Unlock the thread
					typVars.typTimers[i].mRunning = 0;

					if (!typVars.typTimers[i].mBRecuring)
					{	// Once off timer, Null the Pointer so that it doesn't execute again
						typVars.typTimers[i].mFncPtr = NULL;
					}
					typVars.typTimers[i].mOverflowCnt -= typVars.typTimers[i].mOverflowReq;
				}
			}
		}
	}

//	mGlobalData.mCPUInfo.nTicks += inb(TICKS_CNT);

	typVars.nStatus = FALSE;
}

